React’s Secret Weapon: useSyncExternalStore for Seamless State Management

React’s useSyncExternalStore hook provides a powerful and elegant way to integrate external data sources into your React components. This hook allows your components to seamlessly react to updates outside of the typical React state management ecosystem, making it exceptionally useful for handling a wide variety of dynamic scenarios.
Beyond useState and useEffect
In the past, synchronizing external stores with React components often involved using useState to manage the external value and useEffect to synchronize that state with updates from the external source. While this approach works, it can lead to some code complexity.
Let’s consider the example of tracking a user’s online status:
The useSyncExternalStore hook streamlines this process, as the following code snippet demonstrates:
with the help of useSyncExternalStore api it becomes much easier to listen to non-react changes like:
  1. browser events such online, scroll, storage, geolocation, media queries, document visibility, and device battery Status
  1. BehaviorSubject changes from rxjs
  1. actor states in xstate

Essential Concepts

The useSyncExternalStore hook takes two key parameters:
  • subscribe(callback): A function where you subscribe to the external store. The callback function provided by React must be called whenever the store's state changes, signaling React to re-render the component. This callback forms a critical bridge between React and the external world.
  • getSnapshot(): This function returns the current value from the external store. React uses this during the rendering process to ensure consistency.

Code Examples

Let’s explore some common use cases for useSyncExternalStore:

Browser APIs (Network Status)

When there is a change to the internet connection, either online or offline, the callback function will be executed. This is crucial because the callback function acts as a bridge between React and external code. It must be called to notify React about the change and trigger a re-render.

Browser APIs (Storage events)

notion image
In this example, the component will update whenever you type anything into the input box.
notion image
This works because the getSnapshot function retrieves the current value stored in local storage under the key 'input'. The subscribe function passes the callback function to the browser's storage event, and also returns a function to later cancel this event subscription.
notion image
Importantly, we need to manually dispatch the storage event. This is because the storage event doesn’t automatically fire when a change is made in the current tab. (For more information, please see this link: https://developer.mozilla.org/en-US/docs/Web/API/Window/storage_event)."

rxjs BehaviorSubject example

notion image
The UI in this example is straightforward. You have two buttons that can either increase or decrease the value displayed above them. Each button click directly updates the value within the store.
notion image
The implementation of useStore leverages useSyncExternalStore and a BehaviorSubject. We initialize a BehaviorSubject with a starting value of 0 and then connect it to React using useSyncExternalStore. Whenever the BehaviorSubject's value changes, the subscribe function receives the latest update. Importantly, this is where we provide the callback function to the subscribe function.
notion image

Xstate Actor example

The UI in this example remains the same as in the BehaviorSubject example. If you’re new to XState, don’t worry — its logic is designed to be intuitive.
notion image
First, we set up and create the machine. The initial ‘count’ value in the context is 0. When a ‘change’ event occurs, we simply update the count with the value passed to the event. After creating the machine, we use createActor to make an instance of it and initiate it with the start method. Any subscribers will receive updated values whenever changes happen, and this is where we provide the callback function.
notion image
Updating the ‘count’ value within the context is also straightforward. We send an event named ‘change’ along with the desired target value.
notion image

Conclusion

The useSyncExternalStore hook proves itself a powerful tool for connecting non-React state sources to your React components without the complexities of useState and useEffect. In the future, as you need to synchronize your application with third-party libraries, external data sources, or browser-level events, useSyncExternalStore will be an invaluable asset – provided you have a way to get the current value and receive updates from those sources. However, remember to use this power judiciously. For simpler state interactions, useState remains a perfectly valid solution.
Feel free to explore and experiment with it as much as you’d like.

© ming 2021 - 2025